import json
from common.settings import logger
import requests
from typing import Dict, Union
from common.constant import RequestType, ApiInfo, UploadApiField, ParamsType
from urllib.parse import quote
from utils.otherUtils.file_control import check_file_path


class RequestHandler:

    def __init__(self, api_info: Dict):
        self.api_info = api_info

    @property
    def api_describe(self) -> Union[str, None]:
        return self.api_info.get(ApiInfo.DESCRIBE.value)

    @property
    def api_request_type(self) -> Union[str, None]:
        return self.api_info.get(ApiInfo.REQUEST_TYPE.value)

    @property
    def api_host(self) -> Union[str, None]:
        return self.api_info.get(ApiInfo.HOST.value)

    @property
    def api_url(self) -> Union[str, None]:
        return self.api_info.get(ApiInfo.URL.value)

    @property
    def api_method(self) -> Union[str, None]:
        return self.api_info.get(ApiInfo.METHOD.value)

    @property
    def api_headers(self) -> Union[Dict, None]:
        return self.api_info.get(ApiInfo.HEADERS.value)

    def check_api_info(self) -> None:
        if not self.api_request_type:
            raise ValueError('requestType为空')
        if not self.api_host:
            raise ValueError('host为空')
        if not self.api_url:
            raise ValueError('url为空')
        if not self.api_method:
            raise ValueError('method为空')
        if not self.api_headers:
            raise ValueError('headers为空')

    def join_params(self, payload: Dict) -> str:
        params = '?' if self.api_request_type == RequestType.PATH_PARAMS.value else ''
        for item in payload.items():
            # 将小数位是0的浮点数转换为整数，如：将1.0转换为1，再转换为字符串
            if isinstance(item[1], float):
                if item[1] - int(item[1]) == 0:
                    params += item[0] + '=' + str(int(item[1])) + '&'
                else:
                    params += item[0] + '=' + str(item[1]) + '&'
            # 将整数转换为字符串
            elif isinstance(item[1], int):
                params += item[0] + '=' + str(item[1]) + '&'
            else:
                # 如果字符串中有中文或特殊字符等，需要转换为符合URL格式的编码
                params += item[0] + '=' + quote(item[1], encoding='utf-8') + '&'
        return params[:-1]

    def path_params_type_request(self, payload: Dict) -> str:
        self.check_api_info()
        path_params = self.join_params(payload)
        logger.info(f'接口描述：{self.api_describe}')
        logger.info(f'接口url：{self.api_host + self.api_url + path_params}')
        logger.info(f'接口headers：{self.api_headers}')
        try:
            response = requests.request(method=self.api_method, url=self.api_host + self.api_url + path_params,
                                        headers=self.api_headers)
            logger.info(f'接口响应结果：{response.text}')
            return response.text
        except Exception as e:
            logger.error(e)

    def form_type_request(self, payload: Dict) -> str:
        self.check_api_info()
        payload = self.join_params(payload)
        logger.info(f'接口描述：{self.api_describe}')
        logger.info(f'接口url：{self.api_host + self.api_url}')
        logger.info(f'接口headers：{self.api_headers}')
        logger.info(f'接口payload: {payload}')
        try:
            response = requests.request(method=self.api_method, url=self.api_host + self.api_url,
                                        headers=self.api_headers, data=payload)
            logger.info(f'接口响应结果：{response.text}')
            return response.text
        except Exception as e:
            logger.error(e)

    def json_type_request(self, payload: Dict) -> str:
        self.check_api_info()
        logger.info(f'接口描述：{self.api_describe}')
        logger.info(f'接口url：{self.api_host + self.api_url}')
        logger.info(f'接口headers：{self.api_headers}')
        logger.info(f'接口payload: {payload}')
        try:
            response = requests.request(method=self.api_method, url=self.api_host + self.api_url,
                                        headers=self.api_headers, data=json.dumps(payload))
            logger.info(f'接口响应结果：{response.text}')
            return response.text
        except Exception as e:
            logger.error(e)

    def file_type_request(self, payload: Dict, upload_info: Dict) -> str:
        self.check_api_info()
        upload_file_path = upload_info.get(UploadApiField.FILE_PATH.value)
        upload_file_path = check_file_path(upload_file_path)
        upload_params_type = upload_info.get(UploadApiField.PARAMS_TYPE.value)

        logger.info(f'接口描述：{self.api_describe}')
        if upload_params_type:
            # 除了上传文件，还需要传路径参数
            if upload_params_type == ParamsType.PATH_PARAMS.value:
                params = '?' + self.join_params(payload)
                logger.info(f'接口url：{self.api_host + self.api_url + params}')
                logger.info(f'接口headers：{self.api_headers}')
                logger.info(f'上传文件的路径：{upload_file_path}')
                try:
                    with open(upload_file_path, 'rb') as file:
                        response = requests.request(method=self.api_method, url=self.api_host + self.api_url + params,
                                                    headers=self.api_headers, files={'file': file})
                        logger.info(f'接口响应结果：{response.text}')
                        return response.text
                except Exception as e:
                    logger.error(e)
            # 除了上传文件，还需要传表单参数
            elif upload_params_type == ParamsType.FORM.value:
                params = self.join_params(payload)
                logger.info(f'接口url：{self.api_host + self.api_url}')
                logger.info(f'接口headers：{self.api_headers}')
                logger.info(f'上传文件的路径：{upload_file_path}')
                logger.info(f'接口payload: {payload}')
                try:
                    with open(upload_file_path, 'rb') as file:
                        response = requests.request(method=self.api_method, url=self.api_host + self.api_url,
                                                    headers=self.api_headers, data=params, files={'file': file})
                        logger.info(f'接口响应结果：{response.text}')
                        return response.text
                except Exception as e:
                    logger.error(e)
            # 除了上传文件，还需要其它类型的参数
            else:
                logger.error(f'需要上传{upload_params_type}类型的参数')
                raise ValueError(f'需要上传{upload_params_type}类型的参数')
        # 除了上传文件，不需要传其它参数
        else:
            logger.info(f'接口url：{self.api_host + self.api_url}')
            logger.info(f'接口headers：{self.api_headers}')
            logger.info(f'上传文件的路径：{upload_file_path}')
            try:
                with open(upload_file_path, 'rb') as file:
                    response = requests.request(method=self.api_method, url=self.api_host + self.api_url,
                                                headers=self.api_headers, files={'file': file})
                    logger.info(f'接口响应结果：{response.text}')
                    return response.text
            except Exception as e:
                logger.error(e)

    def run(self, payload: Dict, upload_info: Dict = None) -> str:
        if self.api_request_type == RequestType.PATH_PARAMS.value:
            return self.path_params_type_request(payload)
        if self.api_request_type == RequestType.FORM.value:
            return self.form_type_request(payload)
        if self.api_request_type == RequestType.JSON.value:
            return self.json_type_request(payload)
        if self.api_request_type == RequestType.FILE.value:
            return self.file_type_request(payload, upload_info)
